/*
**  Shape
*/
if (!$.Engine.Collision.Shape || typeof $.Engine.Collision.Shape === "undefined") $.Engine.Collision.Shape = {};
$.Engine.Collision.Shape.Shape = function (def, body) {
  this.m_R = new $.Engine.Math.Mat2D();
  this.m_position = new $.Engine.Math.Vector2D();
  this.m_userData = def.userData;

  this.m_friction = def.friction;
  this.m_restitution = def.restitution;
  this.m_body = body;

  this.m_proxyId = $.Engine.Collision.Pair.nullProxy;

  this.m_maxRadius = 0.0;

  this.m_categoryBits = def.categoryBits;
  this.m_maskBits = def.maskBits;
  this.m_groupIndex = def.groupIndex;
}
Object.extend($.Engine.Collision.Shape.Shape.prototype, {
  TestPoint: function (p) { return false },

  GetUserData: function () { return this.m_userData; },

  GetType: function () {
    return this.m_type;
  },

  // Get the parent body of this shape.
  GetBody: function () {
    return this.m_body;
  },

  GetPosition: function () {
    return this.m_position;
  },
  GetRotationMatrix: function () {
    return this.m_R;
  },

  // Remove and then add proxy from the broad-phase.
  // This is used to refresh the collision filters.
  ResetProxy: function (broadPhase) { },

  // Get the next shape in the parent body's shape list.
  GetNext: function () {
    return this.m_next;
  },

  DestroyProxy: function () {
    if (this.m_proxyId != $.Engine.Collision.Pair.nullProxy) {
      this.m_body.m_world.m_broadPhase.DestroyProxy(this.m_proxyId);
      this.m_proxyId = $.Engine.Collision.Pair.nullProxy;
    }
  },

  // Internal use only. Do not call.
  Synchronize: function (position1, R1, position2, R2) { },
  QuickSync: function (position, R) { },
  Support: function (dX, dY, out) { },
  GetMaxRadius: function () {
    return this.m_maxRadius;
  },

  m_next: null,

  m_R: new $.Engine.Math.Mat2D(),
  m_position: new $.Engine.Math.Vector2D(),

  m_type: 0,

  m_userData: null,

  m_body: null,

  m_friction: null,
  m_restitution: null,

  m_maxRadius: null,

  m_proxyId: 0,
  m_categoryBits: 0,
  m_maskBits: 0,
  m_groupIndex: 0
});

$.Engine.Collision.Shape.Shape.Create = function (def, body, center) {
  switch (def.type) {
    case this.e_circleShape:
      {
        return new b2CircleShape(def, body, center);
      }

    case this.e_boxShape:
    case this.e_polyShape:
      {
        return new $.Engine.Collision.Shape.PolyShape(def, body, center);
      }
  }
  return null;
};
$.Engine.Collision.Shape.Shape.Destroy = function (shape) {
  if (shape.m_proxyId != $.Engine.Collision.Pair.nullProxy)
    shape.m_body.m_world.m_broadPhase.DestroyProxy(shape.m_proxyId);
};
$.Engine.Collision.Shape.Shape.e_unknownShape = -1;
$.Engine.Collision.Shape.Shape.e_circleShape = 0;
$.Engine.Collision.Shape.Shape.e_boxShape = 1;
$.Engine.Collision.Shape.Shape.e_polyShape = 2;
$.Engine.Collision.Shape.Shape.e_meshShape = 3;
$.Engine.Collision.Shape.Shape.e_shapeTypeCount = 4;
$.Engine.Collision.Shape.Shape.PolyMass = function (massData, vs, count, rho) {
  var center = new $.Engine.Math.Vector2D(0.0, 0.0);
  var area = 0.0;
  var I = 0.0;

  // pRef is the reference point for forming triangles.
  // It's location doesn't change the result (except for rounding error).
  var pRef = new $.Engine.Math.Vector2D(0.0, 0.0);

  var inv3 = 1.0 / 3.0;

  for (var i = 0; i < count; ++i) {
    // Triangle vertices.
    var p1 = pRef;
    var p2 = vs[i];
    var p3 = i + 1 < count ? vs[i + 1] : vs[0];

    var e1 = $.Engine.Math.SubtractVV(p2, p1);
    var e2 = $.Engine.Math.SubtractVV(p3, p1);

    var D = $.Engine.Math.CrossVV(e1, e2);

    var triangleArea = 0.5 * D;
    area += triangleArea;

    // Area weighted centroid
    // center += triangleArea * inv3 * (p1 + p2 + p3);
    var tVec = new $.Engine.Math.Vector2D().SetV(p1).Add(p2).Add(p3).Multiply(inv3 * triangleArea);
    center.Add(tVec);

    var px = p1.x;
    var py = p1.y;
    var ex1 = e1.x;
    var ey1 = e1.y;
    var ex2 = e2.x;
    var ey2 = e2.y;

    var intx2 = inv3 * (0.25 * (ex1 * ex1 + ex2 * ex1 + ex2 * ex2) + (px * ex1 + px * ex2)) + 0.5 * px * px;
    var inty2 = inv3 * (0.25 * (ey1 * ey1 + ey2 * ey1 + ey2 * ey2) + (py * ey1 + py * ey2)) + 0.5 * py * py;

    I += D * (intx2 + inty2);
  }

  // Total mass
  massData.mass = rho * area;

  // Center of mass
  center.Multiply(1.0 / area);
  massData.center = center;

  // Inertia tensor relative to the center.
  I = rho * (I - area * $.Engine.Math.Dot(center, center));
  massData.I = I;
};

$.Engine.Collision.Shape.Shape.PolyCentroid = function (vs, count, out) {
  var cX = 0.0;
  var cY = 0.0;
  var area = 0.0;

  // pRef is the reference point for forming triangles.
  // It's location doesn't change the result (except for rounding error).
  var pRefX = 0.0;
  var pRefY = 0.0;
  /*
  // This code would put the reference point inside the polygon.
  for (var i = 0; i < count; ++i)
  {
  //pRef += vs[i];
  pRef.x += vs[i].x;
  pRef.y += vs[i].y;
  }
  pRef.x *= 1.0 / count;
  pRef.y *= 1.0 / count;
  */

  var inv3 = 1.0 / 3.0;

  for (var i = 0; i < count; ++i) {
    // Triangle vertices.
    var p1X = pRefX;
    var p1Y = pRefY;
    var p2X = vs[i].x;
    var p2Y = vs[i].y;
    var p3X = i + 1 < count ? vs[i + 1].x : vs[0].x;
    var p3Y = i + 1 < count ? vs[i + 1].y : vs[0].y;

    var e1X = p2X - p1X;
    var e1Y = p2Y - p1Y;
    var e2X = p3X - p1X;
    var e2Y = p3Y - p1Y;

    var D = (e1X * e2Y - e1Y * e2X);

    var triangleArea = 0.5 * D;
    area += triangleArea;

    // Area weighted centroid
    cX += triangleArea * inv3 * (p1X + p2X + p3X);
    cY += triangleArea * inv3 * (p1Y + p2Y + p3Y);
  }

  // Centroid
  cX *= 1.0 / area;
  cY *= 1.0 / area;

  out.Set(cX, cY);
};
